[Android][Framework]Provision


Provision是什么?

Provision的作用很简单,就是一个系统初始化引导程序,源生的Android里面Provision只做了一件事,就是写入一个DEVICE_PROVISIONED标记。

这个标记作用很大,这个标记只会在系统 全新升级(双清)的时候写入一次,代表了Android系统升级准备完成,可以正常工作。

Provision在哪?

一般在package目录下:package/apps/Provision

Proision代码

Provision下只有一个Activity文件和一个Manifest文件

Manifest


  
      
          
          
          
      
  

配置说明:

  • android:excludeFromRecents="true" 不在Recents界面显示。
  • <intent-filter android:priority="1"> 优先级高于Launcher,所以会先于Launcher启动(因为系统Launcher没有显式设置priority值,所以默认是0)
  • category.HOME 桌面程序标记,和Launcher属于一个级别

Activity

public class DefaultActivity extends Activity
{
  @Override
  protected void onCreate(Bundle icicle)
  {
      super.onCreate(icicle);

      // Add a persistent setting to allow other apps to know the device has been provisioned.
      Settings.Secure.putInt(getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 1);

      // remove this activity from the package manager.
      PackageManager pm = getPackageManager();
      ComponentName name = new ComponentName(this, DefaultActivity.class);
      pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
          PackageManager.DONT_KILL_APP);

      // terminate the activity.
      finish();
  }
}

源生代码很简单
做了两件事:

  1. 设置DEVICE_PROVISIONED标记
  2. 禁止Provision自己的Activity组件

对这个代码做点说明:

// Add a persistent setting to allow other apps to know the device has been provisioned.
Settings.Secure.putInt(getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 1);

注释表述很清楚:为设备写入持久的数据,并供其他App了解设备已经provision过。

class Settings

The Settings provider contains global system-level device preferences.

class Secure

Secure system settings, containing system preferences that applications can read but are not allowed to write. These are for preferences that the user must explicitly modify through the system UI or specialized APIs for those values, not modified directly by applications.

public static boolean putInt(ContentResolver cr, String name, int value)

Convenience function for updating a single settings value as an integer. This will either create a new entry in the table if the given name does not exist, or modify the value of the existing row with that name. Note that internally setting values are always stored as strings, so this function converts the given value to a string before storing it.

  • @param cr The ContentResolver to access.
  • @param name The name of the setting to modify.
  • @param value The new value for the setting.
  • @return true if the value was set, false on database errors

禁止组件的功能

pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
    PackageManager.DONT_KILL_APP);

public abstract void setComponentEnabledSetting(ComponentName componentName,
int newState, int flags);

Set the enabled setting for a package component (activity, receiver, service, provider). This setting will override any enabled state which may have been set by the component in its manifest.

  • @param componentName The component to enable

  • @param newState The new enabled state for the component. The legal values for this state are:

    • COMPONENT_ENABLED_STATE_ENABLED

    • COMPONENT_ENABLED_STATE_DISABLED

    • COMPONENT_ENABLED_STATE_DEFAULT

      The last one removes the setting, thereby restoring the component’s state to whatever was set in it’s manifest (or enabled, by default).

  • @param flags Optional behavior flags: DONT_KILL_APP or 0.

功能禁止后,系统package信息会记录下来,保存在 /data/system/packages.xml









这段代码就是记录的禁止DefaultActivity的信息。所以这个组件只会运行一次,之后就被禁止运行了。除非格式化/data/目录。

5X实现

/**
* Application that sets the provisioned bit, like SetupWizard does.
*/
public class DefaultActivity extends Activity {
  private static final String ORIGINAL_LAUNCHER_PACKAGENAME = "com.android.launcher3";
  private static final String ORIGINAL_LAUNCHER_CLASSNAME = "com.android.launcher3.Launcher";
  @Override
  protected void onCreate(Bundle icicle) {
      super.onCreate(icicle);

      // Add a persistent setting to allow other apps to know the device has been provisioned.
      Settings.Global.putInt(getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 1);
      Settings.Secure.putInt(getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, 1);

      // remove this activity from the package manager.
      PackageManager pm = getPackageManager();
      ComponentName name = new ComponentName(this, DefaultActivity.class);

      pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
              PackageManager.DONT_KILL_APP);
      //set Launcher3 as the preferred home activity
      setupDefaultLauncher(pm);
      // terminate the activity.
      finish();
  }

  private void setupDefaultLauncher(PackageManager pm){
      Intent queryIntent = new Intent();
      queryIntent.addCategory(Intent.CATEGORY_HOME);
      queryIntent.setAction(Intent.ACTION_MAIN);  // 查找符合 Launcher 的 activity

      List homeActivities = pm.queryIntentActivities(queryIntent, 0);
      if(homeActivities == null) {
          return;
      }

      ComponentName defaultLauncher = new ComponentName(ORIGINAL_LAUNCHER_PACKAGENAME,
              ORIGINAL_LAUNCHER_CLASSNAME);
      int activityNum = homeActivities.size();
      ComponentName[] set = new ComponentName[activityNum];
      int defaultMatch = -1;
      for(int i = 0; i < activityNum; i++){ //从符合 Launcher 中查找 Launcher3
          ResolveInfo info = homeActivities.get(i);
          set[i] = new ComponentName(info.activityInfo.packageName, info.activityInfo.name);
          if(ORIGINAL_LAUNCHER_CLASSNAME.equals(info.activityInfo.name)
                  && ORIGINAL_LAUNCHER_PACKAGENAME.equals(info.activityInfo.packageName)){
              defaultMatch = info.match;
          }
      }

      //if Launcher3 is not found, do not set anything
      if(defaultMatch == -1){
          return;
      }
      IntentFilter filter = new IntentFilter();
      filter.addAction(Intent.ACTION_MAIN);
      filter.addCategory(Intent.CATEGORY_HOME);
      filter.addCategory(Intent.CATEGORY_DEFAULT);

      pm.addPreferredActivity(filter, defaultMatch, set, defaultLauncher);
  }
}

Reference
Android 初始化Setup Wizard——Provision


文章作者: Wossoneri
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC 4.0 许可协议。转载请注明来源 Wossoneri !
评论
  目录